package com.hurl.waguji.biz.schedule;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.testng.log4testng.Logger;

/**
 * 定时任务
 * @author hurl
 *
 */
public class ScheduleService {
	private static final Logger log = Logger.getLogger(ScheduleService.class);
	private static final String JOB_GROUP = "WAGUJI";
	private static final String TRIGGER_GROUP = "WAGUJI";

	public static final String KEY_PARAM_DETAIL = "detail";
	
	private static Scheduler s = init();
	
	private static Scheduler init(){
		try {
			return StdSchedulerFactory.getDefaultScheduler();
		} catch (SchedulerException e) {
			log.error(e.getMessage(),e);
			throw new ScheduleRuntimeException("初始化Scheduler时遇到错误："+e.getMessage(),e);
		}
	}
	
	/**
	 * 删除所有任务。
	 * @throws SchedulerException
	 */
	public static void unscheduleAllJobs() throws ScheduleException{
		try {
			s.clear();
		} catch (SchedulerException e) {
			log.error(e.getMessage(),e);
			throw new ScheduleException(e.getMessage(),e);
		}
	}
	public static void shutdown()throws ScheduleRuntimeException{
		try {
			s.shutdown();
		} catch (SchedulerException e) {
			log.error(e.getMessage(),e);
			throw new ScheduleRuntimeException(e.getMessage(),e);
		}
	}
	public static boolean pauseJob(String jobName){
		try {
			s.pauseJob(JobKey.jobKey(jobName, JOB_GROUP));
			return true;
		} catch (SchedulerException e) {
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 启动计划任务，该过程就从数据库中加载定时任务。
	 * @throws SchedulerException
	 */
	public static void start(){
		try {
			log.info("加载定时任务。。。");
			s.start();
			log.info("加载完成！");
		} catch (SchedulerException e) {
			log.info("加载失败！");
			log.error(e.getMessage(),e);
			throw new ScheduleRuntimeException(e.getMessage(),e);
		}
	}
	public static void scheduleProcessJob(ProcessJobDetail detail)throws ScheduleException{
		try {
			if(s.checkExists(JobKey.jobKey(detail.getIdentifier().getId(), JOB_GROUP))){
				throw new ScheduleException("已经存在同名的任务！");
			}
			JobDataMap dataMap = new JobDataMap();
			dataMap.put(ScheduleService.KEY_PARAM_DETAIL,detail);
			/* 构建JobDetail */
			JobDetail jobDetail = JobBuilder.newJob(ProcessJob.class)
					.withIdentity(detail.getIdentifier().getId(), JOB_GROUP)
					.usingJobData(dataMap)
					.withDescription(detail.getIdentifier().getTitle())
					.build();
			
			/* 构建Trigger */
			CronTrigger trigger = TriggerBuilder.newTrigger()
					.withIdentity(detail.getIdentifier().getId(), TRIGGER_GROUP)
					.forJob(jobDetail)
					.withSchedule(CronScheduleBuilder.cronSchedule(detail.getCronExpression()))
					.build();
			
			/* 添加定时任务 */
			s.scheduleJob(jobDetail,trigger);
		} catch (SchedulerException e) {
			log.error(e.getMessage());
			throw new ScheduleException("添加任务失败："+e.getMessage());
		}
	}
	private static ProcessJobDetail buildScheduleJobItem(JobDetail detail,CronTrigger trigger) throws SchedulerException{

		ProcessJobDetail jDetail = (ProcessJobDetail)detail.getJobDataMap().get(ScheduleService.KEY_PARAM_DETAIL);
		jDetail.setNextFireTime(trigger.getNextFireTime());
		jDetail.setPreviousFireTime(trigger.getPreviousFireTime());
		TriggerState state = s.getTriggerState(trigger.getKey());
		switch(state){
		case BLOCKED:
			jDetail.setStatus("阻塞");
			break;
		case COMPLETE:
			jDetail.setStatus("完成");
			break;
		case ERROR:
			jDetail.setStatus("出错");
			break;
		case NONE:
			jDetail.setStatus("未知");
			break;
		case NORMAL:
			jDetail.setStatus("正常");
			break;
		case PAUSED:
			jDetail.setStatus("暂停");
			break;
		}
		return jDetail;
	
	}
	private static List<String> getCurrentlyExecutingJobNames() throws SchedulerException{
		List<JobExecutionContext> list = s.getCurrentlyExecutingJobs();
		if(list==null || list.isEmpty())
			return new ArrayList<String>(0);
		
		List<String> jobNames = new ArrayList<String>();
		for(JobExecutionContext context : list){
			jobNames.add(context.getJobDetail().getKey().getName());
		}
		return jobNames;
	}
	public static List<ProcessJobDetail> getAllJobs(){
		try{
		Iterator<TriggerKey> it = s.getTriggerKeys(GroupMatcher.triggerGroupEquals(TRIGGER_GROUP)).iterator();
		List<String> currentlyExecutionJobNames = getCurrentlyExecutingJobNames();
		List<ProcessJobDetail> list = new ArrayList<ProcessJobDetail>();
		while(it.hasNext()){
			TriggerKey key = it.next();
			CronTrigger trigger = (CronTrigger)s.getTrigger(key);
			JobDetail detail = s.getJobDetail(trigger.getJobKey());
			
			ProcessJobDetail item = buildScheduleJobItem(detail, trigger);
			if(currentlyExecutionJobNames.contains(item.getIdentifier().getId())){
				item.setStatus("执行中");
			}
			list.add(item);
		}
		
		return list;
		}catch(SchedulerException e){
			log.error(e);
			throw new ScheduleRuntimeException("获取Job失败",e);
		}
	}
	public static boolean unscheduleJob(String jobName){
		try{
			s.pauseJob(JobKey.jobKey(jobName, JOB_GROUP));
			return s.deleteJob(JobKey.jobKey(jobName, JOB_GROUP));
		}catch(SchedulerException e){
			log.error(e);
			return false;
		}
	}
	public static boolean triggerJob(String jobName){
		try {
			if(getCurrentlyExecutingJobNames().contains(jobName)){
				log.error("任务“"+jobName+"”正在执行中，不能同时进行两个相同的任务。");
				return false;
			}
			s.triggerJob(JobKey.jobKey(jobName,JOB_GROUP));
			return true;
		} catch (SchedulerException e) {
			log.error("启动任务失败",e);
			return false;
		}
	}
	public static List<ProcessJobDetail> getCurrentlyExecutingJobs(){
		try {
			List<JobExecutionContext> list = s.getCurrentlyExecutingJobs();
			if(list==null || list.isEmpty()){
				return null;
			}
			List<ProcessJobDetail> itemList = new ArrayList<ProcessJobDetail>(list.size());
			ProcessJobDetail item = null;
			for(JobExecutionContext context : list){
				item = buildScheduleJobItem(context.getJobDetail(),(CronTrigger)context.getTrigger());
				itemList.add(item);
			}
			return itemList;
			
		} catch (SchedulerException e) {
			e.printStackTrace();
			throw new ScheduleRuntimeException("获取当前正在执行的任务时出错！",e);
		}
	}
}
